Skip to content

fix(AttemptCompletionTool): child tasks return to parent when parent status is active#510

Merged
edelauna merged 3 commits into
mainfrom
debug/parent-subtask-state
Jun 7, 2026
Merged

fix(AttemptCompletionTool): child tasks return to parent when parent status is active#510
edelauna merged 3 commits into
mainfrom
debug/parent-subtask-state

Conversation

@edelauna
Copy link
Copy Markdown
Contributor

@edelauna edelauna commented Jun 6, 2026

Related GitHub Issue

Fixes: #457

Description

Child tasks were failing to return to their parent after calling attempt_completion in v3.56+. The regression was reported on Discord; downgrading to v3.55 restored the behaviour.

Root cause confirmed: Issue #457 describes the exact sequence. When a same-profile child completes and the parent resumes, the parent status is transiently "active" while it awaits the next (different-profile) child. The guard in AttemptCompletionTool previously required parentStatus === "delegated" to proceed. Since the status was "active", the guard rejected the return and the child fell through to standalone completion.

Fix: Both delegation guards now accept "active" in addition to "delegated" when awaitingChildId matches the returning child. Cancellation remains protected because cancellation clears awaitingChildId.

Changes:

  • AttemptCompletionTool: Accept parentStatus === "active" when awaitingChildId matches the returning child.
  • ClineProvider#reopenParentFromDelegation: Same guard relaxation for symmetry.
  • subtasks.test.ts: E2e regression test reproducing the exact Subtask never returns to parent after a per-mode model/profile switch (attempt_completion silently waits for human) #457 sequence — same-profile child returns first, parent delegates to a different-profile child, both complete and parent resumes.
  • attemptCompletionTool.spec.ts: Unit tests covering all guard boundary cases including the new path and the mismatched-awaitingChildId rejection.

Test Procedure

  • Unit tests: 33 passing (completion lifecycle suite)
  • Full extension test suite: 6040 passing
  • E2E subtask suite: 5 passing
  • Type checks: clean

Pre-Submission Checklist

  • Issue Linked: This PR is linked to an approved GitHub Issue (see "Related GitHub Issue" above).
  • Scope: My changes are focused on the linked issue (one major feature/fix per PR).
  • Self-Review: I have performed a thorough self-review of my code.
  • Testing: New and/or updated tests have been added to cover my changes (if applicable).
  • Documentation Impact: I have considered if my changes require documentation updates (see "Documentation Updates" section below).
  • Contribution Guidelines: I have read and agree to the Contributor Guidelines.

Documentation Updates

  • No documentation updates are required.

Additional Notes

The Discord reporter's original trigger has not been reproduced in isolation — history navigation while a child is active produces the same symptom but via a separate path. This PR fixes the confirmed #457 sequence. Diagnostic logging from the first commit remains in place to surface any remaining unknown trigger.

Get in Touch

Discord: edelauna

Summary by CodeRabbit

  • Tests

    • Expanded end-to-end coverage with fast-completing child and cross-profile delegation scenarios; refactored tests for deterministic task sequencing and stronger cleanup.
  • Improvements

    • Resuming parent tasks now recognizes additional parent states when children complete.
    • More informative diagnostics: enhanced log messages (including caller stack snippets) and cleaner fallback behavior when delegation is skipped.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 6, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 86168b83-19c3-491a-a0a8-2329814b8dfb

📥 Commits

Reviewing files that changed from the base of the PR and between d7a98bc and 4610768.

📒 Files selected for processing (2)
  • apps/vscode-e2e/src/fixtures/subtasks.ts
  • apps/vscode-e2e/src/suite/subtasks.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/vscode-e2e/src/fixtures/subtasks.ts
  • apps/vscode-e2e/src/suite/subtasks.test.ts

📝 Walkthrough

Walkthrough

This PR addresses issue #457 by relaxing parent task status checks to accept "active" in addition to "delegated" when awaiting a returning child. The fix modifies delegation resumption logic in both AttemptCompletionTool and ClineProvider, adds provider-based logging for diagnostics, and validates the change with comprehensive unit and E2E test coverage including fast completion and cross-profile subtask scenarios.

Changes

Subtask delegation and cross-profile completion flow

Layer / File(s) Summary
Delegation status guard relaxation
src/core/tools/AttemptCompletionTool.ts, src/core/webview/ClineProvider.ts
DelegationProvider interface gains a log method; status checks in AttemptCompletionTool (line 105) and ClineProvider (line 3545) expand to accept parent status === "active" alongside "delegated" when awaitingChildId matches the returning child.
Delegation diagnostics and error logging
src/core/tools/AttemptCompletionTool.ts, src/core/webview/ClineProvider.ts
Skip-delegation diagnostic messages are now logged via provider.log() with child/parent statuses and awaitingChildId. History-lookup failures use provider.log() instead of console.error(). Caller stack traces are captured in removeClineFromStack for richer delegation-repair messages that log via both this.log() and console.warn().
Unit and integration test updates
src/core/tools/__tests__/attemptCompletionTool.spec.ts, src/__tests__/history-resume-delegation.spec.ts
Delegation test scenarios updated to model parent as "active" with awaitingChildId set to child; mock provider gains log function. New assertions verify "Skipping delegation" logging and standalone completion when delegation should be skipped. Added test case for parent awaiting a different child. Integration test scenario renamed to reflect "active parent awaiting return child".
E2E test fixtures for subtask flows
apps/vscode-e2e/src/fixtures/subtasks.ts
New exported constants define prompt/result markers for fast completion and cross-profile scenarios. Fast-completion fixtures implement immediate child response via attempt_completion. Cross-profile fixtures use predicate-based matching to sequence same-profile code child followed by conditional different-profile ask child, with parent resumption only after both results are present.
E2E test scenarios for subtask completion
apps/vscode-e2e/src/suite/subtasks.test.ts
Updated fixture imports; fast-completion test asserts child emits completion_result and parent resumes with non-empty result. Normal-completion test refactored to track ask/say messages by taskId, wait for child spawn and follow-up prompt, and strengthen stack cleanup. New cross-profile test upserts two profiles, configures sequential mode routing, validates two distinct child completions (same and different profile), and asserts parent resumes with aggregated result; includes enhanced error diagnostics with stack snapshot and per-task message summary.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

  • #369: Overlaps in keeping parents active while children run; changes to delegation/resume logic for "active" parent state directly relate to fan-out work.
  • #366: Shares modifications to task-status/delegation logic in ClineProvider and AttemptCompletionTool (reopen/repair and delegation resumption).
  • #372: Addresses parent-wakeup and fan-out concerns through the same "active" parent state expansion and delegation-resume logging mechanisms.
  • #365: Both modify reopenParentFromDelegation in ClineProvider; this PR broadens allowed parent statuses and adds diagnostics while related issue addresses history update serialization race.

Poem

🐰 A subtask hops home, profile switched mid-quest,
No longer detained by a guard that knows best,
"Active" and "awaiting" now join hands in flight,
Cross-profile children return to the light,
Diagnose wisely, the parent sleeps right!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and specifically describes the main fix: child tasks returning to parent when parent status is active, which directly addresses the regression in v3.56+.
Description check ✅ Passed The description fully follows the template with all required sections: Related GitHub Issue (#457), detailed Description explaining root cause and fix, comprehensive Test Procedure with results, and completed Pre-Submission Checklist.
Linked Issues check ✅ Passed The PR successfully implements the exact requirements from issue #457: both guards (AttemptCompletionTool and ClineProvider.reopenParentFromDelegation) now accept 'active' status when awaitingChildId matches, unit and E2E tests validate the fix, and cancellation protections are preserved.
Out of Scope Changes check ✅ Passed All changes are directly scoped to issue #457: guard relaxations in two completion handlers, regression test in E2E suite, unit test coverage for boundary cases, and fixture extensions for the new test scenario; no unrelated changes detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch debug/parent-subtask-state

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link
Copy Markdown

codecov Bot commented Jun 6, 2026

Codecov Report

❌ Patch coverage is 87.50000% with 2 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/core/tools/AttemptCompletionTool.ts 77.77% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

@edelauna edelauna changed the title chore: add subtask delegation diagnostics fix(AttemptCompletionTool): child tasks return to parent when parent status is active Jun 6, 2026
@edelauna edelauna marked this pull request as ready for review June 6, 2026 17:31
@edelauna edelauna force-pushed the debug/parent-subtask-state branch from 5bc3c89 to d7a98bc Compare June 6, 2026 17:32
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/vscode-e2e/src/fixtures/subtasks.ts`:
- Around line 57-73: The first-turn new_task fixture created via mock.addFixture
that matches on userMessage / SUBTASK_FAST_PARENT_MARKER should include
sequenceIndex: 0 so it only fires once; update that fixture object to add
sequenceIndex: 0 and keep the response.toolCalls entry (id:
"call_subtasks_fast_parent_new_task_001") unchanged. Also tighten the x-profile
resumed-parent fixture predicate so it does not rely on the embedded
SUBTASK_XPROFILE_SAME_CHILD_RESULT string inside SUBTASK_XPROFILE_PARENT_PROMPT;
instead key the matcher to the child completion (for example by matching the
child tool call id or the child tool result field / toolCallId emitted when the
child finishes) so the resumed-parent fixture only triggers after the child tool
call completes.

In `@apps/vscode-e2e/src/suite/subtasks.test.ts`:
- Around line 359-366: The test is overwriting persisted modeApiConfigs and then
clearing them; instead capture the original configuration before calling
api.setConfiguration (e.g., read and store the result of api.getConfiguration or
the current modeApiConfigs into a variable) and in suiteTeardown restore that
saved configuration by calling api.setConfiguration with the saved
modeApiConfigs (instead of setting {}). Update both places that clear configs
(the block around api.upsertProfile / api.setConfiguration and the other
instance at lines 433-435) to save the prior config before mutating and restore
it in the teardown so subsequent suites retain the original routing/default
config.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 3ab8db0d-3d38-44f4-98a2-3228ed0bb671

📥 Commits

Reviewing files that changed from the base of the PR and between 09fedd6 and d7a98bc.

📒 Files selected for processing (6)
  • apps/vscode-e2e/src/fixtures/subtasks.ts
  • apps/vscode-e2e/src/suite/subtasks.test.ts
  • src/__tests__/history-resume-delegation.spec.ts
  • src/core/tools/AttemptCompletionTool.ts
  • src/core/tools/__tests__/attemptCompletionTool.spec.ts
  • src/core/webview/ClineProvider.ts

Comment thread apps/vscode-e2e/src/fixtures/subtasks.ts
Comment thread apps/vscode-e2e/src/suite/subtasks.test.ts
Copy link
Copy Markdown
Contributor

@taltas taltas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice PR

Copy link
Copy Markdown
Contributor

@navedmerchant navedmerchant left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@edelauna edelauna added this pull request to the merge queue Jun 7, 2026
Merged via the queue into main with commit 43935ed Jun 7, 2026
11 checks passed
@edelauna edelauna deleted the debug/parent-subtask-state branch June 7, 2026 12:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Subtask never returns to parent after a per-mode model/profile switch (attempt_completion silently waits for human)

3 participants